import os
from typing import Optional
import h5py
from pydantic import BaseModel
import pandas as pd
from fastapi import APIRouter
from fastapi.responses import JSONResponse
from method import Kline, Log
from config import db

import requests
import json
from fastapi import APIRouter
from fastapi.responses import JSONResponse

router = APIRouter(default_response_class=JSONResponse)

positions = []
profit = 0

def get_exchangeInfo():
    data = []
    keys = 'symbols'
    if os.path.exists(db.exchange_info):
        # 读取数据文件（'r' 表示只读）
        with h5py.File(db.exchange_info, 'r') as f:
            if keys in f:
                # 读取嵌套组中的数据集
                data_list = f[keys][()]
                # 把JSON字符串反序列化回对象
                data = json.loads(data_list.decode('utf-8'))
    return data

def get_tick_and_step(filters: list[dict]) -> tuple[float, float]:
    tick_size = None
    step_size = None
    print(filters)
    for f in filters:
        if f.get("filterType") == "PRICE_FILTER":
            tick_size = f["tickSize"]
        elif f.get("filterType") == "LOT_SIZE":
            step_size = f["stepSize"]
    def get_precision_from_step(step_str: str) -> int:
        """根据 tickSize 或 stepSize 字符串返回允许的小数位数"""
        if '.' not in step_str:
            return 0
        return len(step_str.rstrip('0').split('.')[1])
    tick_size = get_precision_from_step(tick_size)
    step_size = get_precision_from_step(step_size)
    return tick_size, step_size

def set_order_df(current, klineLast, symbol):
    global positions
    global profit
    order_list = {}
    exists = next((item for item in positions if item['symbol'] == symbol), None)
    klineLast = current[-1]
    mas = Kline.Indicator(current)
    price = float(klineLast['Close'])
    indicator = {
        'ma7': float(mas.MA_line(7)),
        'ma25': float(mas.MA_line(25)),
    }

    # 判断是否存在仓位，存在仓位不再买入
    if exists and abs(float(exists['positionAmt'])) > 0:
        entry_price = float(exists['entryPrice'])
        stop_price = False
        stop_ma = False
        # 判断当前是否已经到达止盈止损位置，进行平仓
        if exists['positionSide'] == 'LONG':
            stop_price = (price - entry_price) / entry_price if (price < entry_price and (entry_price - price) / entry_price > 0.005) else stop_price
            stop_price = (price - entry_price) / entry_price if (price > entry_price and (price - entry_price) / entry_price > 0.015) else stop_price
            stop_ma = price < indicator['ma25'] * 0.999
            if stop_ma:
               stop_price = (indicator['ma25'] - entry_price) / entry_price 
        elif exists['positionSide'] == 'SHORT':
            stop_price = (entry_price - price) / entry_price if (price > entry_price and (price - entry_price) / entry_price > 0.005) else stop_price
            stop_price = (entry_price - price) / entry_price if (price < entry_price and (entry_price - price) / entry_price > 0.015) else stop_price
            stop_ma = price > indicator['ma25'] * 1.001
            if stop_ma:
               stop_price = (entry_price - indicator['ma25']) / entry_price 
        # 止损/止盈
        if stop_price:
            exchangeInfo = get_exchangeInfo()
            info = next((item for item in exchangeInfo if item['symbol'] == symbol), None)
            tick, step = get_tick_and_step(info['filters'])
            Log.set_log(json.dumps({
                'positionSide': exists['positionSide'],
                'side': 'SELL' if exists['positionSide'] == 'LONG' else 'BUY',
                'type': 'MARKET',
                'quantity': exists['positionAmt'],
                'symbol': exists['symbol'],
                'entryPrice': exists['entryPrice'],
                'stopPrice': round(indicator['ma25'] if stop_ma else price, tick),
                'profit': stop_price,
                'kline': klineLast,
                'indicator': indicator
            }), 'stop')
            order_list = {
                'positionSide': exists['positionSide'],
                'side': 'SELL' if exists['positionSide'] == 'LONG' else 'BUY',
                'type': 'MARKET',
                'quantity': exists['positionAmt'],
                'symbol': exists['symbol'],
                'entryPrice': float(exists['entryPrice']),
                'stopPrice': round(indicator['ma25'] if stop_ma else price, tick),
                'profit': stop_price,
                'amount': 50 * 30 * stop_price,
                'kline': klineLast,
                'indicator': indicator
            }
            positions = []
            profit = profit + stop_price
            Log.set_log(f'单次下单营收：{stop_price}，总营收：{profit}', 'profit')
    else:
        cross = mas.cross_line()
        slope = abs((indicator['ma7'] - indicator['ma25']) / indicator['ma7'])
        if cross == 'golden_cross':
            exchangeInfo = get_exchangeInfo()
            info = next((item for item in exchangeInfo if item['symbol'] == symbol), None)
            tick, step = get_tick_and_step(info['filters'])
            # 金叉上涨
            Log.set_log(json.dumps({
                'positionSide': 'LONG',
                'side': 'BUY',
                'type': 'MARKET',
                'symbol': symbol,
                'quantity': round(float(50) / float(klineLast['Close']) * float(50), step),
                'entryPrice': round((price + indicator['ma7']) / 2, tick),
                'klineLast': klineLast,
                'slope': slope,
                'indicator': indicator
            }), 'backtest')
            order_list = {
                'positionSide': 'LONG',
                'side': 'BUY',
                'type': 'MARKET',
                'symbol': symbol,
                'positionAmt': round(float(50) / float(klineLast['Close']) * float(30), step),
                'quantity': round(float(50) / float(klineLast['Close']) * float(30), step),
                'entryPrice': round((price + indicator['ma7']) / 2, tick),
                'slope': slope,
                'kline': klineLast,
                'indicator': indicator
            }
            positions = [order_list]
        elif cross == 'death_cross':
            exchangeInfo = get_exchangeInfo()
            info = next((item for item in exchangeInfo if item['symbol'] == symbol), None)
            tick, step = get_tick_and_step(info['filters'])
            # 死叉下跌
            Log.set_log(json.dumps({
                'positionSide': 'SHORT',
                'side': 'SELL',
                'type': 'MARKET',
                'symbol': symbol,
                'quantity': round(float(50) / float(klineLast['Close']) * float(50), step),
                'entryPrice': round((price + indicator['ma7']) / 2, tick),
                'klineLast': klineLast,
                'slope': slope,
                'indicator': indicator
            }), 'backtest')
            order_list = {
                'positionSide': 'SHORT',
                'side': 'SELL',
                'type': 'MARKET',
                'symbol': symbol,
                'positionAmt': round(float(50) / float(klineLast['Close']) * float(30), step),
                'quantity': round(float(50) / float(klineLast['Close']) * float(30), step),
                'entryPrice': round((price + indicator['ma7']) / 2, tick),
                'slope': slope,
                'kline': klineLast,
                'indicator': indicator
            }
            positions = [order_list]
    return order_list

class Cross(BaseModel):
    symbol: Optional[str] = ''
    interval: Optional[str] = ''
    limit: Optional[int] = None 

@router.post("/cross")
def back_test(param: Cross):
    global profit
    global positions
    params = {
        'symbol': param.symbol,
        'interval': param.interval,
        'limit': param.limit or 300
    }

    response = requests.get("https://fapi.binance.com/fapi/v1/klines", params=params)
    data = response.json()

    # 将数据转换为DataFrame
    df = pd.DataFrame(data, columns=[
        "OpenTime", "Open", "High", "Low", "Close", "Volume",
        "CloseTime", "QuoteVolume", "Trades", "TakerBuyBaseVolume",
        "TakerBuyQuoteVolume", "Ignore"
    ])
    df = df.drop(columns=["Ignore", "Trades", "QuoteVolume", "TakerBuyQuoteVolume"])
    # 转换时间戳为日期时间格式
    df['OpenTime'] = pd.to_datetime(df['OpenTime'], unit='ms').dt.tz_localize("UTC").dt.tz_convert("Asia/Shanghai").dt.strftime('%Y-%m-%d %H:%M')
    df['CloseTime'] = pd.to_datetime(df['CloseTime'], unit='ms').dt.tz_localize("UTC").dt.tz_convert("Asia/Shanghai").dt.strftime('%Y-%m-%d %H:%M')

    # 将DataFrame转换为JSON格式
    result = df.to_dict(orient='records')
    order_list = []
    # 回测
    for i in range(30, len(result) + 1):
        current = result[:i]
        klineLast = current[-1]
        order = set_order_df(current, klineLast, param.symbol)
        if order:
            order_list.append(order)
    profit = 0
    positions = []
    return order_list
